//
//  UIImage+PHA.m
//  TestDemo
//
//  Created by fengxijun on 16/6/8.
//  Copyright © 2016年 goappbox. All rights reserved.
//

#import "UIImage+PHA.h"
#import "ImageHash.h"

@implementation UIImage (PHA)

//截取部分图像
-(UIImage*)getSubImage:(CGRect)rect
{
    CGImageRef subImageRef = CGImageCreateWithImageInRect(self.CGImage, rect);
    CGRect smallBounds = CGRectMake(0, 0, CGImageGetWidth(subImageRef), CGImageGetHeight(subImageRef));
    
    UIGraphicsBeginImageContext(smallBounds.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextDrawImage(context, smallBounds, subImageRef);
    UIImage* smallImage = [UIImage imageWithCGImage:subImageRef];
    UIGraphicsEndImageContext();
    
    return smallImage;
}

//等比例缩放
-(UIImage*)scaleToSize:(CGSize)size
{
//    CGFloat width = CGImageGetWidth(self.CGImage);
//    CGFloat height = CGImageGetHeight(self.CGImage);
//    
//    CGFloat sx = size.width * 1.0 / width;
//    CGFloat sy = size.height * 1.0 / height;
//    
//    CGFloat radio = 1;
//    if(sy>1 && sx>1)
//    {
//        radio = sy > sx ? sx : sy;
//    }
//    else
//    {
//        radio = sy < sx ? sy : sx;
//    }
//    
//    width = width * radio;
//    height = height * radio;
//    
//    int xPos = (size.width - width) / 2;
//    int yPos = (size.height - height) / 2;
//    
//    // 创建一个bitmap的context
//    // 并把它设置成为当前正在使用的context
//    UIGraphicsBeginImageContext(size);
//    
//    // 绘制改变大小的图片
//    [self drawInRect:CGRectMake((int)xPos, (int)yPos, size.width, size.height)];
//    
//    // 从当前context中创建一个改变大小后的图片
//    UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
//    
//    // 使当前的context出堆栈
//    UIGraphicsEndImageContext();
//    
//    // 返回新的改变大小后的图片
//    return scaledImage;
    
    UIGraphicsBeginImageContext(size);
    [self drawInRect:CGRectMake(0.f, 0.f, size.width, size.height)];
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return scaledImage;

}

//第二步，简化色彩。
//将缩小后的图片，转为64级灰度。也就是说，所有像素点总共只有64种颜色。
- (UIImage *)grayImage
{
    size_t width = self.size.width;
    size_t height = self.size.height;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
    CGContextRef context = CGBitmapContextCreate (nil, (size_t)width, (size_t)height, 8, 0, colorSpace, kCGImageAlphaNone);
    CGColorSpaceRelease(colorSpace);
    if (context == NULL) {
        return nil;
    }
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), self.CGImage);
    UIImage *grayImage = [UIImage imageWithCGImage:CGBitmapContextCreateImage(context)];
    CGContextRelease(context);
    return grayImage;
}

- (unsigned char *)imageToData
{
//    size_t width = CGImageGetWidth(self.CGImage);
//    size_t height = CGImageGetHeight(self.CGImage);
    
    size_t width = self.size.width;
    size_t height = self.size.height;
    
    char *buffer = malloc(4*width*height);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef contextRef = CGBitmapContextCreate(buffer, width, height, 8, 4*width, colorSpace, kCGImageAlphaPremultipliedLast);
    CGImageRef imageRef = self.CGImage;
    CGContextDrawImage(contextRef, CGRectMake(0, 0, width, height), imageRef);
    unsigned char *tmp = CGBitmapContextGetData(contextRef);
    CGContextRelease(contextRef);
    CGColorSpaceRelease(colorSpace);
    return tmp;
}

- (UIImage *)grayImage64
{
    unsigned char *tmp = [self imageToData];
    CGFloat width = self.size.width;
    CGFloat height = self.size.height;
    for (int i = 0; i < width; i++) {
        for (int j = 0; j < height; j++) {
            int index = j*width*4 + 4*i;
            int r = (unsigned char)tmp[index];
            int g = (unsigned char)tmp[index+1];
            int b = (unsigned char)tmp[index+2];
//            float grey = 0.299*r + 0.587*g + 0.114*b;
            float grey = 0.299*r + 0.587*g + 0.114*b;
            tmp[index] = grey;
            tmp[index + 1] = grey;
            tmp[index + 2] = grey;
        }
    }
    
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef contextRef = CGBitmapContextCreate(tmp, width, height, 8, 4*width, colorSpace, kCGImageAlphaPremultipliedLast);
    CGImageRef imageRef = CGBitmapContextCreateImage(contextRef);

    UIImage *grayImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    CGContextRelease(contextRef);
    CGColorSpaceRelease(colorSpace);
    return grayImage;
    
//    unsigned char *data = [self imageToData];
//    CGFloat width = self.size.width;
//    CGFloat height = self.size.height;
//    for (int i = 0; i < width; i++) {
//        for (int j = 0; j < height; j++) {
//            int index = j*width*4 + 4*i;
//            UInt32 rgba = 0x0;
//            memcpy(&rgba, &data[index], sizeof(UInt32));
//            int r = data[index];
//            int g = data[index+1];
//            int b = data[index+2];
//            int _red = (r << 16) & 0xFF0000;
//            int _green = (g << 8) & 0xFF00;
//            int _blue = (b) & 0xFF;
//            UInt32 rgbt = _red+ _green + _blue;
//            NSLog(@"r : %0x : b : %0x",rgba >> 8,rgbt);
//            CGFloat gray = [ImageHash rgbToGray:rgbt];
//            data[index] = gray;
//            data[index + 1] = gray;
//            data[index + 2] = gray;
//        }
//    }
//    
////    for (size_t i = 0; i < pixelCount; i++) {
////        //        UInt32 value = pixels[i];
////        UInt32 rgba = pixels[i * 4];
////        UInt32 gray = [ImageHash rgbToGray:rgba];
////        memcpy(&pixels[i*4], &gray, sizeof(UInt32));
////        NSLog(@"idx %zu grayValue : old : %0X : grayValue : %0X", i, rgba,gray);
////    }
//    
//    
//    CGColorSpaceRef colorSpacea = CGColorSpaceCreateDeviceRGB();
//    CGContextRef contextRefa = CGBitmapContextCreate(data, width, height, 8, 4*width, colorSpacea, kCGImageAlphaPremultipliedLast);
//    CGImageRef imageRefa = CGBitmapContextCreateImage(contextRefa);
//    UIImage *image = [UIImage imageWithCGImage:imageRefa scale:self.scale orientation:self.imageOrientation];
//    CGImageRelease(imageRefa);
//    CGContextRelease(contextRefa);
//    CGColorSpaceRelease(colorSpacea);
//    
//    
//    
//    return image;


    
//    //下面的代码创建要输出的图像的相关参数
//    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, width * height * 4, NULL);
//    // prep the ingredients
////    int bitsPerComponent = 8;
////    int bitsPerPixel = 32;
//    // 5. Cleanup
//    CGColorSpaceRelease(colorSpace);
//    CGContextRelease(context);
//    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
//    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
//    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
//    //创建要输出的图像
//    CGImageRef imageRef = CGImageCreate(width, height,
//                                        bitsPerComponent,
//                                        bitsPerComponent * bytesPerPixel,
//                                        width * 4,
//                                        colorSpaceRef,
//                                        bitmapInfo,
//                                        provider,
//                                        NULL, NO, renderingIntent);
//    UIImage *mosaicImage = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
//    CFRelease(imageRef);
//    CGColorSpaceRelease(colorSpaceRef);
//    CGDataProviderRelease(provider);
    
//    return mosaicImage;
    
}

- (NSData *)imageContentData
{
    size_t width = CGImageGetWidth(self.CGImage);
    size_t height = CGImageGetHeight(self.CGImage);
    NSData *imageData = UIImagePNGRepresentation(self);
//    NSData *data = [imageData subdataWithRange:NSMakeRange(imageData.length - width * height * 4, width * height * 4)];
    NSLog(@"data : length -> %lu : %@",(unsigned long)[imageData length],imageData);
    unsigned char *tmp = [self imageToData];
    NSData *dataWithByte = [NSData dataWithBytes:tmp length:width * height * 4];
    return dataWithByte;
}

- (UIImage *)getImageFromLast25bByte
{
    size_t width = CGImageGetWidth(self.CGImage);
    size_t height = CGImageGetHeight(self.CGImage);
    NSData *imageData = UIImageJPEGRepresentation(self, 1.0);
    NSInteger length = width * height;
    NSData *data = [imageData subdataWithRange:NSMakeRange(imageData.length - length * 4, length * 4)];
    NSLog(@"data : length -> %lu : %@",(unsigned long)[data length],data);
    unsigned char *tmp = malloc(length * 4);
    memcpy(tmp, &data.bytes[imageData.length - length * 4], length * 4);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef contextRef = CGBitmapContextCreate(tmp, width, height, 8, 4*width, colorSpace, kCGImageAlphaPremultipliedLast);
    CGImageRef imageRef = CGBitmapContextCreateImage(contextRef);
    
    UIImage *grayImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    CGContextRelease(contextRef);
    CGColorSpaceRelease(colorSpace);
    return grayImage;
}

- (NSString *)hashCode {
    
    CGImageRef thumbImageRef = self.CGImage;
    unsigned char *tmp = [self imageToData];
    
    size_t width = CGImageGetWidth(thumbImageRef);
    size_t height = CGImageGetHeight(thumbImageRef);
    size_t length = width * height;
    UInt32 *pixels = malloc(length * 4);
    
    for (int i = 0; i < width; i++) {
        for (int j = 0; j < height; j++) {
            size_t index = j * width*4 + 4*i;
            UInt32 gray = [ImageHash grayWithR:tmp[index] g:tmp[index + 1] b:tmp[index + 2]];
            pixels[i * height + j] = gray;
        }
    }
    
    free(tmp);
    
    // 第三步，计算平均值。
    // 计算所有64个像素的灰度平均值。
    
    UInt32 avgPixel = [ImageHash average:pixels count:length];
    
    // 第四步，比较像素的灰度。
    // 将每个像素的灰度，与平均值进行比较。大于或等于平均值，记为1；小于平均值，记为0。
    Byte *comps = malloc(length);
    for (int i = 0; i < length; i++) {
        if (pixels[i] > avgPixel) {
            comps[i] = 1;
        } else {
            comps[i] = 0;
        }
    }
    
    free(pixels);
    
    // 第五步，计算哈希值。
    // 将上一步的比较结果，组合在一起，就构成了一个64位的整数，这就是这张图片的指纹。组合的次序并不重要，只要保证所有图片都采用同样次序就行了。
    NSMutableString *hashCode = [NSMutableString string];
    for (int i = 0; i < length; i+= 4) {
        UInt32 result = comps[i] * (UInt32) pow(2, 3) + comps[i + 1] * (UInt32) pow(2, 2) + comps[i + 2] * (UInt32) pow(2, 1) + comps[i + 3];
        char ch = [ImageHash binaryToHex:result];
        [hashCode appendFormat:@"%c",ch];
    }
    free(comps);
    return hashCode;
}

//3.计算出图片平均灰度，然后每一点灰度与平均灰度比较，大于平均值是1，小于平均值是0
-(NSString *)pHashValueWithImage {
    NSMutableString * pHashString = [NSMutableString string];
    CGImageRef imageRef = [self CGImage];
    unsigned long width = CGImageGetWidth(imageRef);
    unsigned long height = CGImageGetHeight(imageRef);
    CGDataProviderRef provider = CGImageGetDataProvider(imageRef);
    NSData* data = (id)CFBridgingRelease(CGDataProviderCopyData(provider));
    //    NSLog(@"data = %@",data);
    const char * heightData = (char*)data.bytes;
    int sum = 0;
    
    for (int i = 0; i < width * height; i++)
    {
//        printf("%d ",heightData[i]);
        if (heightData[i] != 0)
        {
            sum += heightData[i];
        }
    }
    int avr = sum / (width * height);
//    NSLog(@"%d",avr);
    for (int i = 0; i < width * height; i++)
    {
        if (heightData[i] >= avr) {
            [pHashString appendString:@"1"];
        }
        else {
            [pHashString appendString:@"0"];
        }
    }
//    NSLog(@"pHashString = %@,pHashStringLength = %lu",pHashString,(unsigned long)pHashString.length);
    return pHashString;
}

- (NSString *)imageFingerPrint
{
//    第一步，缩小尺寸。
//    最快速的去除高频和细节，只保留结构明暗的方法就是缩小尺寸。
//    将图片缩小到8x8的尺寸，总共64个像素。摒弃不同尺寸、比例带来的图片差异。
    UIImage *thumbImage = [self scaleToSize:CGSizeMake(8.0, 8.0)];
    
//    第二步，简化色彩。
//    将缩小后的图片，转为64级灰度。也就是说，所有像素点总共只有64种颜色。
    UIImage *grayImage = [thumbImage grayImage];
    
//    第三步，计算平均值，比较像素的灰度。
//    计算所有64个像素的灰度平均值，将每个像素的灰度，与平均值进行比较，大于或等于平均值，记为1；小于平均值，记为0。
    
    
    return [grayImage pHashValueWithImage];
    
}

//- (NSString *)imageFingerPrint
//{
//    // 第一步，缩小尺寸。
//    // 将图片缩小到8x8的尺寸，总共64个像素。这一步的作用是去除图片的细节，只保留结构、明暗等基本信息，摒弃不同尺寸、比例带来的图片差异。
//    UIImage *thumbImage = [self scaleToSize:CGSizeMake(8.0, 8.0)];
//    
//    // 第二步，简化色彩。
//    // 将缩小后的图片，转为64级灰度。也就是说，所有像素点总共只有64种颜色。
//    
//    return [thumbImage hashCode];
//    
//}

static CGContextRef CreateRGBABitmapContext (CGImageRef inImage)
{
    CGContextRef context = NULL;
    CGColorSpaceRef colorSpace;
    void *bitmapData; //内存空间的指针，该内存空间的大小等于图像使用RGB通道所占用的字节数。
    size_t bitmapByteCount;
    size_t bitmapBytesPerRow;
    
    size_t pixelsWide = CGImageGetWidth(inImage); //获取横向的像素点的个数
    size_t pixelsHigh = CGImageGetHeight(inImage);
    
    bitmapBytesPerRow = (pixelsWide * 4); //每一行的像素点占用的字节数，每个像素点的ARGB四个通道各占8个bit(0-255)的空间
    bitmapByteCount = (bitmapBytesPerRow * pixelsHigh); //计算整张图占用的字节数
    
    colorSpace = CGColorSpaceCreateDeviceRGB();//创建依赖于设备的RGB通道
    //分配足够容纳图片字节数的内存空间
    bitmapData = malloc( bitmapByteCount );
    //创建CoreGraphic的图形上下文，该上下文描述了bitmaData指向的内存空间需要绘制的图像的一些绘制参数
    context = CGBitmapContextCreate (bitmapData,
                                     pixelsWide,
                                     pixelsHigh,
                                     8,
                                     bitmapBytesPerRow,
                                     colorSpace,
                                     kCGImageAlphaPremultipliedLast);
    //Core Foundation中通过含有Create、Alloc的方法名字创建的指针，需要使用CFRelease()函数释放
    CGColorSpaceRelease( colorSpace );
    return context;
}

static unsigned char *RequestImagePixelData(UIImage *inImage)
{
    CGImageRef img = [inImage CGImage];
    CGSize size = [inImage size];
    //使用上面的函数创建上下文
    CGContextRef cgctx = CreateRGBABitmapContext(img);
    
    CGRect rect = {{0,0},{size.width, size.height}};
    //将目标图像绘制到指定的上下文，实际为上下文内的bitmapData。
    CGContextDrawImage(cgctx, rect, img);
    unsigned char *data = CGBitmapContextGetData (cgctx);
    //释放上面的函数创建的上下文
    CGContextRelease(cgctx);
    return data;
}

+ (UIImage *)mosaicImage:(UIImage *)image withLevel:(int)level
{
    unsigned char *imgPixel = RequestImagePixelData(image);
    CGImageRef inImageRef = [image CGImage];
    size_t width = CGImageGetWidth(inImageRef);
    size_t height = CGImageGetHeight(inImageRef);
    unsigned char prev[4] = {0};
    size_t bytewidth = width * 4;
    int i,j;
    int val = level;
    for(i=0;i<height;i++) {
        if (((i+1)%val) == 0) {
            memcpy(imgPixel+bytewidth*i, imgPixel+bytewidth*(i-1), bytewidth);
            continue;
        }
        for(j=0;j<width;j++) {
            if (((j+1)%val) == 1) {
                memcpy(prev, imgPixel+bytewidth*i+j*4, 4);
                continue;
            }
            memcpy(imgPixel+bytewidth*i+j*4, prev, 4);
        }
    }
    NSInteger dataLength = width*height* 4;
    
    //下面的代码创建要输出的图像的相关参数
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, imgPixel, dataLength, NULL);
    // prep the ingredients
    int bitsPerComponent = 8;
    int bitsPerPixel = 32;
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
    //创建要输出的图像
    CGImageRef imageRef = CGImageCreate(width, height,
                                        bitsPerComponent,
                                        bitsPerPixel,
                                        bytewidth,
                                        colorSpaceRef,
                                        bitmapInfo,
                                        provider,
                                        NULL, NO, renderingIntent);
    UIImage *mosaicImage = [UIImage imageWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation];
    CFRelease(imageRef);
    CGColorSpaceRelease(colorSpaceRef);
    CGDataProviderRelease(provider);
    return mosaicImage;
}

//- (UIImage *)getImageWithBytes:(unsigned char *)bytes length:(size_t)dataLength
//{
//    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bytes, dataLength, NULL);
//    
//    int bitsPerComponent = 8;
//    int bitsPerPixel = 32;
//    
//    
//}

@end
